package com.google.android.apps.skipbot;

import roboguice.inject.InjectView;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Toast;
import android.widget.ToggleButton;

public class SkipperPhone extends SkipperActivity implements TextWatcher {
  protected static final String TAG = "Skipper";

  @InjectView(R.id.servo)
  SeekBar servo;
  @InjectView(R.id.park)
  Button park;
  @InjectView(R.id.stand)
  Button stand;

  @InjectView(R.id.forward_left_walk)
  Button forwardLeftWalk;
  @InjectView(R.id.forward_walk)
  Button forwardWalk;
  @InjectView(R.id.forward_right_walk)
  Button forwardRightWalk;
  @InjectView(R.id.left_walk)
  Button leftWalk;
  @InjectView(R.id.stop)
  Button stop;
  @InjectView(R.id.right_walk)
  Button rightWalk;
  @InjectView(R.id.back_left_walk)
  Button backLeftWalk;
  @InjectView(R.id.back_walk)
  Button backWalk;
  @InjectView(R.id.back_right_walk)
  Button backRightWalk;

  @InjectView(R.id.servo_selector)
  EditText servoPinEditor;
  @InjectView(R.id.attach)
  ToggleButton attachButton;
  @InjectView(R.id.pose_launcher)
  Button poseLauncher;
  @InjectView(R.id.quit)
  Button quitButton;

  private int servoPin;
  private GaitType gaitType = GaitType.TRIPOD;
  private PreferencesListener preferencesListener;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    servoPinEditor.addTextChangedListener(this);

    quitButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        stopService(new Intent(SkipperPhone.this, RobotService.class));
        finish();
      }
    });

    poseLauncher.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Intent intent = new Intent(SkipperPhone.this, PoseCreatorActivity.class);
        startActivity(intent);
      }
    });

    attachButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {
      @Override
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {
          robotService.getRobot().attachAllServos();
        } else {
          robotService.getRobot().detachAllServos();
        }
      }
    });

    servo.setProgress(servo.getMax() / 2);
    servo.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
        robotService.getRobot().detachServo(servoPin);
      }

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {
        if (robotService.getRobot() != null) {
          robotService.getRobot().attachServoToPin(0, servoPin);
        }
      }

      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (servoPin >= 2 && servoPin <= 48) {
          robotService.getRobot().moveServo(0, progress);
        }
      }
    });

    park.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Toast.makeText(SkipperPhone.this, "Sitting", Toast.LENGTH_SHORT).show();
        Log.d(TAG, "Parking");
        robotService.getRobot().sit();
      }
    });

    forwardLeftWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Forward Left");
        ((SkipperRobot) (robotService.getRobot())).move(Math.PI * 7.0 / 4.0, gaitType);
      }
    });

    forwardWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Forward");
        ((SkipperRobot) (robotService.getRobot())).move(0.0, gaitType);
      }
    });

    forwardRightWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Forward Right");
        ((SkipperRobot) (robotService.getRobot())).move(Math.PI / 4.0, gaitType);
      }
    });

    leftWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Left");
        ((SkipperRobot) (robotService.getRobot())).move(Math.PI * 3.0 / 2.0, gaitType);
      }
    });

    stop.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Stop");
        robotService.getRobot().stop();
      }
    });

    rightWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Right");
        ((SkipperRobot) (robotService.getRobot())).move(Math.PI / 2.0, gaitType);
      }
    });

    backLeftWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Backward Left");
        ((SkipperRobot) (robotService.getRobot())).move(Math.PI * 5.0 / 4.0, gaitType);
      }
    });

    backWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Backward");
        ((SkipperRobot) (robotService.getRobot())).move(Math.PI, gaitType);
      }
    });

    backRightWalk.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Log.d(TAG, "Backward Right");
        ((SkipperRobot) (robotService.getRobot())).move(Math.PI * 3.0 / 4.0, gaitType);
      }
    });

    stand.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Toast.makeText(SkipperPhone.this, "Standing", Toast.LENGTH_SHORT).show();
        Log.d(TAG, "Standing");
        robotService.getRobot().stand();
      }
    });

    setEnabled(robotService != null);
    if (robotService == null) {
      // TODO(dkhawk) show an alert dialog instead
      Toast.makeText(this, "Please connect robot", Toast.LENGTH_SHORT).show();
    }

    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

    // Make sure that when preferences change that the robot settings get updated.
    // Note that you have to explicitly keep a reference to this listener because
    // the listeners are stored in a weak hash map and will be GCed otherwise.
    preferencesListener = new PreferencesListener();
    sharedPreferences.registerOnSharedPreferenceChangeListener(preferencesListener);
  }

  @Override
  protected void onResume() {
    super.onResume();
    updateRobotFromPreferences();
  }

  protected void updateRobotFromPreferences() {
    // Sync up the internal settings with the user preferences.
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    updateRobotConfig(sharedPreferences.getString(SkipperPreferences.OPT_ROBOT_CONFIG,
        SkipperPreferences.SKIPPER_LARGE));
    updateRobotGait(sharedPreferences.getString(SkipperPreferences.OPT_ROBOT_GAIT, "Tripod"));
  }

  @Override
  void onRobotConnected() {
    Toast.makeText(this, R.string.robot_service_connected, Toast.LENGTH_SHORT).show();
    updateRobotFromPreferences();
    setEnabled(true);
  }

  @Override
  void onRobotDisconnected() {
    Toast.makeText(this, R.string.robot_service_disconnected, Toast.LENGTH_SHORT).show();
    setEnabled(false);
  }

  /**
   * Enables/Disables all of controls in the main UI.
   */
  private void setEnabled(boolean enabled) {
    servo.setEnabled(enabled);
    park.setEnabled(enabled);
    stand.setEnabled(enabled);
    forwardWalk.setEnabled(enabled);
    leftWalk.setEnabled(enabled);
    rightWalk.setEnabled(enabled);
    backWalk.setEnabled(enabled);
    stop.setEnabled(enabled);
    servoPinEditor.setEnabled(enabled);
    attachButton.setEnabled(enabled);
    poseLauncher.setEnabled(enabled);
  }

  @Override
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  }

  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
    try {
      servoPin = Integer.parseInt(s.toString());
    } catch (NumberFormatException e) {
    }
  }

  @Override
  public void afterTextChanged(Editable s) {
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      case R.id.menu_settings:
        startActivity(new Intent(this, SkipperPreferences.class));
        return true;
    }
    return false;
  }

  /**
   * Updates the robot config based on the parameter.
   */
  private void updateRobotConfig(String robotConfig) {
    if (robotService != null) {
      robotService.setRobotConfig(this, robotConfig);
    }
  }

  /**
   * Updates the robot gait based on the parameter.
   */
  private void updateRobotGait(String robotGait) {
    if (robotGait.equals("Tripod")) {
      gaitType = GaitType.TRIPOD;
    } else if (robotGait.equals("Ripple")) {
      gaitType = GaitType.RIPPLE;
    } else if (robotGait.equals("Staggered")) {
      gaitType = GaitType.STAGGERED;
    } else {
      Log.d(TAG, "Unknown Gait: " + robotGait);
    }
  }

  /**
   * Listens to changes in the default preferences and updates the related robot
   * settings accordingly.
   */
  private class PreferencesListener implements SharedPreferences.OnSharedPreferenceChangeListener {
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
      if (key.equals(SkipperPreferences.OPT_ROBOT_CONFIG)) {
        updateRobotConfig(sharedPreferences.getString(key, SkipperPreferences.SKIPPER_LARGE));
      } else if (key.equals(SkipperPreferences.OPT_ROBOT_GAIT)) {
        updateRobotGait(sharedPreferences.getString(key, "Tripod"));
      }
    }
  }

}
